#include "GcovManager.hpp"
#include "main.hpp"
#include "WriteExcelManager.hpp"

#include <sstream>
#include <iomanip>
#include <filesystem>

#define DF_STRINGIFY(x) #x
#define DF_STR(x) DF_STRINGIFY(x)

DEFINE_UT_DEBUG;

constexpr const char *ENV_ZUT_NO_FORCE_GCC_VERSION = "ZUT_NO_FORCE_GCC_VERSION";

namespace
{
    bool getEnvDataPath();
    bool fileExists(const std::string &path);
    [[maybe_unused]] bool isForceGccVersion();
    [[maybe_unused]] std::string exec(const char *cmd);
} // namespace

int main(int argc, char const *argv[])
{
    std::string currentPath = std::string(argv[0], strrchr(argv[0], '\\') - argv[0]);

    exclog::logpath = currentPath + std::string("/log.txt");

    exclog::getEnvLog();

    LOG("log path is %s", exclog::logpath.c_str());
    std::filesystem::path path = exclog::logpath;
    std::filesystem::remove(path);

    std::string xml_path;
    std::string gcov_path;
    std::string demo_excel_path;

    if (getEnvDataPath())
    {
        LOG("evn ZUT_DATA_PATH is have.");

#ifdef CURRENT_DIR
        if (fileExists(DF_STR(CURRENT_DIR) "\\UT_execute.xml"))
            xml_path = DF_STR(CURRENT_DIR) "\\UT_execute.xml";

        if (fileExists(DF_STR(CURRENT_DIR) "\\gcov.txt"))
            gcov_path = DF_STR(CURRENT_DIR) "\\gcov.txt";

        if (fileExists(DF_STR(CURRENT_DIR) "\\Template_1.0.xlsx"))
            demo_excel_path = DF_STR(CURRENT_DIR) "\\Template_1.0.xlsx";
#endif // CURRENT_DIR

        if (xml_path.empty())
        {
            if (fileExists(std::string(currentPath) + std::string("\\UT_execute.xml")))
                xml_path = std::string(currentPath) + std::string("\\UT_execute.xml");
        }
        if (gcov_path.empty())
        {
            if (fileExists(std::string(currentPath) + std::string("\\gcov.txt")))
                gcov_path = std::string(currentPath) + std::string("\\gcov.txt");
        }

        if (demo_excel_path.empty())
        {
            if (fileExists(std::string(currentPath) + std::string("\\Template_1.0.xlsx")))
                demo_excel_path = std::string(currentPath) + std::string("\\Template_1.0.xlsx");
        }
    }
    else
    {
        if (argc < 2)
        {
            return -1;
        }
        else
        {
            xml_path = argv[1];
            gcov_path = argv[2];
            demo_excel_path = "./Template.xlsx";
        }
    }

    int gcc_majorVersion = 15;
    int gcc_minorVersion = 1;

    // TODO GCC版本检查
#if 0    
    if (isForceGccVersion())
    {
        std::string gcc_version = exec("gcc --version | head -n 1");
        if (gcc_version.empty())
        {
            LOG("not gcc compiler!!");
            gcc_majorVersion = gcc_minorVersion = -1;
        }
        else
        {
            const char *begin = strrchr(gcc_version.c_str(), ' ');
            if (begin == nullptr)
            {
                LOG("can not get gcc version. %s", gcc_version.c_str());
            }
            else
            {
                begin++; // skip ' '
                const char *majorVersion = strchr(begin, '.');
                const char *minorVersion = strchr(majorVersion + 1, '.');
                try
                {
                    gcc_majorVersion = std::stoi(std::string(begin, majorVersion));
                    gcc_minorVersion = std::stoi(std::string(majorVersion + 1, minorVersion));
                }
                catch (const std::invalid_argument &e)
                {
                    LOG("Invalid argument: %s", e.what());
                }
                catch (const std::out_of_range &e)
                {
                    LOG("Out of range: %s", e.what());
                }
            }
        }
    }
    else
    {
        LOG("not force gcc version");
    }
#endif

    LOG("xml_path: %s", xml_path.c_str());
    LOG("gcov_path: %s", gcov_path.c_str());
    LOG("demo_excel_path: %s", demo_excel_path.c_str());

    /* gcc的版本与gcov的版本是强关联的 */
    std::shared_ptr<gcov::GcovManager> gcovManager = std::make_shared<gcov::GcovManager>(
        static_cast<gcov::GcovMajorVersion>(gcc_majorVersion), static_cast<gcov::GcovMinorVersion>(gcc_minorVersion));
    std::shared_ptr<wxlsx::ExcelUtInfoList> resMap = gcovManager->readXmlGcov(xml_path, gcov_path);

    std::shared_ptr<wxlsx::WriteExcelManager> writeExcelManager = std::make_shared<wxlsx::WriteExcelManager>(wxlsx::WEXCEL_1_0);

    writeExcelManager->write_xlsx(demo_excel_path, argv[0], resMap);

    return 0;
}

namespace
{
    bool getEnvDataPath()
    {
        char *env = getenv("ZUT_DATA_PATH");
        return env != nullptr;
    }
    bool fileExists(const std::string &path)
    {
        return std::filesystem::exists(path);
    }

    [[maybe_unused]] bool isForceGccVersion()
    {
        char *env = getenv(ENV_ZUT_NO_FORCE_GCC_VERSION);
        LOG("force gcc evn is %s", env);
        return env == nullptr;
    }

    [[maybe_unused]] std::string exec(const char *cmd)
    {
        std::array<char, 128> buffer;
        std::string result;
        FILE *pipe = popen(cmd, "r");
        if (!pipe)
            throw std::runtime_error("popen() failed!");
        try
        {
            while (fgets(buffer.data(), buffer.size(), pipe) != nullptr)
            {
                LOG("data is %s", buffer.data());
                result += buffer.data();
            }
        }
        catch (...)
        {
            pclose(pipe);
            throw;
        }
        pclose(pipe);
        return result;
    }

} // namespace